使用 getaddrinfo()
getaddrinfo()
是一个高层的接口,它可以用来处理 DNS 查询、地址解析等任务。使用这个接口非常简单,不需要手动构建 DNS 查询报文。
1 | // dnsReq.c |
编译:gcc -o dnsReq dnsReq.c
运行:./dnsReq hostname_1 hostname_2 hostname_3 ... ...
手动构造 DNS 查询报文
DNS 查询和回答报文具有相同的格式。
DNS 报文首部占 12 个字节。
- 前 16 比特标识,事务 ID,用于标识请求和响应之间的匹配。客户端和服务器在发送和接收查询时会使用该 ID。
- Flags :标志字段,指示查询类型、响应状态等。
- QR:1 位,表示查询(0)还是响应(1)。
- Opcode:4 位,表示查询的类型(标准查询、反向查询等)。
- 0:标准查询(Standard query)。这是最常见的查询类型,用于获取指定域名的IP地址或其他DNS记录。
- 1:反向查询(Inverse query)。这种查询类型通常用于根据IP地址获取对应的域名,与标准查询相反。
- 2:服务器状态请求(Status request)。这种查询类型用于请求DNS服务器的状态信息,通常用于诊断或监控目的。
- AA:1 位,表示是否为权威答案(1 表示是)。
- TC:1 位,表示响应是否被截断(通常用于 TCP 响应)。
- RD:1 位,表示是否要求递归查询(1 表示要求)。
- RA:1 位,表示是否支持递归查询(1 表示支持)。
- zero:3 位,保留,通常为 0。
- rCode:4 位,响应码,表示查询的状态(成功、无数据等)。
- 0:无差错。表示DNS查询成功完成,没有遇到任何问题。
- 1:格式差错(Format error)。这表示服务器不能理解请求的报文格式,可能是由于报文格式不正确或存在无法识别的字段。
- 2:域名服务器失败(Server failure)。这表示由于服务器的原因导致无法处理请求,可能是由于服务器内部错误或资源不足等原因。
- 3:名字错误(Name Error)。这表示解析的域名不存在,只有对授权域名解析服务器有意义。它指出客户端请求的域名在DNS系统中不存在或无法找到。
- 4:查询类型不支持(Not Implemented)。这表示域名服务器不支持客户端请求的查询类型。
- 5:拒绝(Refused)。这表示服务器由于设置的策略拒绝给出应答,例如服务器不希望对某些请求者给出应答。
- Number of questions:表示查询中的问题数目,通常为 1,表示只查询一个域名的记录。
- Number of anwser RRs:表示响应中答案的数量。在查询报文中,这个字段一般为 0。
- Number of anthority RRs:表示响应中权威记录的数量。
- Number of additional RRs:表示响应中附加记录的数量。
DNS 查询部分(Question Section)
查询部分包含一个或多个问题,通常情况下一个 DNS 查询只包含一个问题。该部分包括域名和查询的类型。每个问题由以下字段组成:
字段 | 描述 | 长度(字节) |
---|---|---|
QNAME | 查询的域名,格式为标签(label)加点(’.’)。 | 可变 |
QTYPE | 查询类型,表示想要查询的记录类型(如 A、MX)。 | 2 |
QCLASS | 查询类,表示查询的类,通常为 IN(Internet)。 | 2 |
QNAME (查询的域名)
QNAME
是一个以点(.
)分隔的标签(label)格式的域名。例如,如果查询 www.example.com
,QNAME
就是由标签 www
、example
、com
组成的。
每个标签之前有一个字节表示该标签的长度(例如 “www” 对应的标签长度为 3,”example” 长度为 7)。最终,域名以一个 0x00
字节结束,表示域名的结尾。
QTYPE (查询类型)
QTYPE
是一个 16 位的字段,表示查询的记录类型。常见的查询类型有:
类型 | 描述 | 代码 |
---|---|---|
A | IPv4 地址 | 1 |
AAAA | IPv6 地址 | 28 |
MX | 邮件交换记录 | 15 |
CNAME | 别名记录 | 5 |
NS | 域名服务器记录 | 2 |
PTR | 反向查询记录 | 12 |
QCLASS (查询类)
QCLASS
是一个 16 位的字段,表示查询的类。通常查询类为 IN(互联网),其值为 1。
类别 | 描述 | 代码 |
---|---|---|
IN | Internet(互联网) | 1 |
CH | Chaos(用于 Chaosnet) | 3 |
HS | Hesiod(Hesiod 系统) | 4 |
Answer Section (答案部分)
答案部分包含 DNS 响应的资源记录。每个资源记录由以下字段组成:
字段 | 描述 | 长度(字节) |
---|---|---|
NAME | 域名(通常是指向查询的域名或子域名)。 | 可变 |
TYPE | 记录类型(如 A 记录、MX 记录)。 | 2 |
CLASS | 类别(通常是 IN)。 | 2 |
TTL | 生存时间(Time to Live),表示记录在缓存中的有效时间(单位是秒)。 | 4 |
RDLENGTH | 数据的长度。 | 2 |
RDATA | 记录数据,存储具体的信息(如 IP 地址)。 | 可变 |
DNS answer section:TYPE 类型字段有以下常用值:
A记录(Address Record)
- TYPE字段值为1。
- 表示将域名映射到IPv4地址。
NS记录(Name Server Record)
- TYPE字段值为2。
- 指定域名服务器负责特定区域的权威信息。
CNAME记录(Canonical Name Record)
- TYPE字段值为5。
- 提供域名的规范别名,通常用于将一个域名重定向到另一个域名。
PTR记录(Pointer Record)
- TYPE字段值为12。
- 用于反向DNS查询,将IP地址映射到域名。
MX记录(Mail Exchange Record)
- TYPE字段值为15。
- 指定邮件服务器的优先级和域名,用于邮件路由。
AAAA记录
- TYPE字段值为28。
- 类似于A记录,但用于将域名映射到IPv6地址。
SRV记录
- TYPE字段值为33。
- 指定提供特定服务的服务器的位置,包括主机名、端口号和优先级等信息。
TXT记录
- TYPE字段值为16。
- 提供任意文本信息,通常用于存储元数据或说明性信息。
NAPTR记录(Naming Authority Pointer Record)
- TYPE字段值为35。
- 用于基于正则表达式的域名到URI的映射。
TLSA记录
- TYPE字段值为863。
- 用于存储DNSSEC(域名系统安全扩展)的TLS证书关联信息。
C语言代码发起 DNS 查询报文
1 | // dnsReq.c |
环境在 Linux 发送版 Ubuntu 下,编译器使用 gcc,
编译命令: gcc -o dnsReq dnsReq.c
运行:命令行下 ./dnsReq
,./
表示当前目录,dnsReq
编译后的可执行文件。
运行以上代码:构造了一个 DNS 查询报文(查询 baidu.com),并使用 socket 套接字编程连接谷歌公共 DNS 服务器 8.8.8.8
的 53
端口,发送了该 DNS 查询报文,将得到的响应以二进制的形式写入文件 output.bin
中。
一下是对该二进制文件的分析:
1 | 2136 8180 0001 0002 0000 0000 0562 6169 !6...........bai |
2136
ID8180
Flags,意思是: 响应报文、递归查询、支持递归查询、响应成功。0001
Number of questions :1个查询。0002
Number of answers:2个应答。0000
Number of anthority RRs :00000
Number of additional RRs :00562 6169 6475 0363 6f6d 0000 0100 01
代码中构造的 DNS 查询,请见代码。c0 0c00 0100 0100 0000 9000 046e f244 42
第一条应答:- NAME:
c0 0c
表示域名的指针,前两个 bit 为11
,后面14个 bit 的值为 12,表示域名在整个应答报文中的偏移量,偏移量的下标从 0 开始,也就是第 12 个字节处,正好指向 baidu.com - TYPE:
00 01
表示 A 记录。 - CLASS:
00 01
表示 IN (Internet 互联网) - TTL:
00 0000 90
生存时间,16*9 秒。 - RDLENGTH:
00 04
数据长度 4 个字节。 - RDDATA:
6e f244 42
4个字节的数据,写成点分十进制就是110.242.68.66
- NAME:
c0 0c00 0100 0100 0000 9000 0427 9c42 0a
第二条应答:数据部分写成点分十进制就是39.156.66.10
验证:
DNS 应答报文如果最后多出了一个 0a 字节,则表示换行,表示应答报文的结束。
拿到二进制数据,自己手动去翻译应答报文实属麻烦,写代码解析 DNS 应答报文的任务,就交给屏幕前正在阅读此文的你。